HTML-based Interfaces

Nik Swoboda
Indiana University
Dept of Computer Science, Lindley Hall
Bloomington, IN 47405
nswoboda@cs.indiana.edu


Introduction

This document describes how to build graphical, form-based interfaces for end-user programs using HTML and CGI. HTML is used only to describe the look and feel of the user interface, many programming languages can be used to write the program itself. We will illustrate this by showing example programs written in C, C++, PERL, and PASCAL. This document is intended for an audience that does have prior knowledge of the writing of documents and forms in HTML. If you are not so qualified please refer to the following links.

Organization

Why build HTML-based interfaces?

Today, we are living in a multi-platform world in which everyone wants to create applications that are platform independent. This can be done with expensive cross-compilers and expensive GUI generating software packages. But why not take advantage of other people's hard work and make things easy for yourself by using HTML. There is no reason why you and everyone else has to keep writing the "same" (more or less) code for generating windows, buttons, boxes, pictures, etc. You would like to be able to make an input field as easily as writing < input name="inp"> , which can be done in HTML. You should not have to write code to handle selecting text in the window, or code to make the input "clickable". Your web browser will take care of all of that for you. Thus, ultimately, when you use HTML forms you only have to describe the way that you want the interface to look and you leave the work of generating it to the web browser.

What needs to be done?

Your interface will contain two main parts: a form which will obtain some type of useful information, and a program that will perform some type of computation on that information ultimately writing its results into yet another HTML document. Basically our main goal is to learn how to write these programs. They will be written to take CGI style input from our forms and generate output as HTML documents which can be accessed through your favorite web browser.

Why not just write a GUI?

The main reason for using HTML as a front end for your programming projects is that by doing so you are taking advantage of the fact that there exist Web brousers for virtually every platform that you might be interested in having your software running on. So as long as you have a compiler that can create executable code for the target machine which can "run from the command line" and there exists a web browser for that platform and presentation environment, the modifications to use HTML are minimal. In fact these modifications do not necessarily require the re-compiling of the executables, scripting languages like Perl can be used as a "wrapper" for the existing code.

What will I need to get started?

Nota bene: All of the examples used in this document are written in a C like syntax, following each example there will be links to the sources of "real" code in various languages and using various CGI libraries.

At this point if you are not that familiar to writing HTML documents you might want to take a quick side trip to learn some basics. ( Ncsa'a Primer would be a good place to start.) Being confortable with CGI would also help the learning process along. Yahoo's CGI list is another good resource of CGI information.

Is it really this easy? (Tutorial with Code Examples)

Quick links to examples:

Assorted CGI programs of interest

Hello World Program

Well as tradition dictates we will start our little lesson with a Hello World! program.

The traditional Hello World program in C looks like the following:

#include < stdio.h>

main()
    { printf("Hello World!");}

When you compile and run the above program it writes "Hello World!" to the standard output. Now we have to make a few simple changes to the code in order to be able to access the program through a web browser. When the browser encounters a CGI program, like ours, it basically executes it and sends the program's output to your web browser. Therefore we need to set up our program to simply output to standard out a HTML document. To do this we need to add two printf's around the Hello World! containing < html > and < /html > respecively. Now there is only one last thing which must be done: identify the document type to the web browser. To do this the first line outputed by the program must be "Content-Type: text/html", this must be followed by two newline's.

After including these changes the final HTML ready C code for the Hello program will look like this:

#include <.h> 



main() {
        printf("Content-type: text/html\n\n");
        printf("<>");
        printf("Hello World!");
        printf("</html>"); }



Output and examples in other languages

Note: for the remaining examples I will be using C like syntax but taking some obvious shortcuts to make the code more readable. If something is not clear take a look at the real source.

If at this point you are not sure how to use your web browser to look a the output of the program that you have just written take a look at Appendix B - How to use your browser to open your application

Bounce - a simple echo program

Now we will move onto a program that generates a simple one input form and echoes back the information typed into that form. Normally when people write forms, they write a form and then a script that parses the output from the form. I personally think that this is unnecessary, there is no reason why you need to have two parts. I think that it is best to combine both the form and the form processor into one program.

We will write one program that will be executed twice, once to generate the form, and yet again to echo the form's contents in a HTML document. The question that remains is how does the program know which "mode" (form generating or form result computing) it will be running in? Simply a request for the form will not transmit any data to the program and a request for computation will send data. You leave the process of determining whether there is input to the form up to the CGI libraries that you will be using.

In the main section of the program there will be a simple conditional which will decide whether there is input to the program or not. If there is no input the program will generate the HTML form, and if there is input the program will do it's required computation and return the results in a HTML document. The following illustrates this process.


main()
{ 
  print content type
  if (there is input) /* you can now generate the output HTML */
       { parse input into variables
         printf("< html> ");
         printf("I got: %s ",input);
         printf("< /html> ");
         return 1;}
  else /* there is no input so generate the form */
      {  printf("< html> ");
         printf("< form method=""post"" action=""this file's name""> ");
         printf("< input name=""input""> ");
         printf("< input type=""submit""> ");
         printf("< /form> ");  
         printf("< /html> ");
         return 1;}
         }

Output and examples in other languages

Notes regarding code:
I did leave out a bunch of detail, like how is the input gotten and put into input? This is a langauge and library specific question, so look at the examples if it is not clear. I did double the "'s that occured within the printf's so that they would not be interpreted as the terminating " of the string.

Multiply - use HTML to help with multiplication

Next we will write a multiplication program with optional rounding option. There is not much more required for writing a more complicated "command line" (one input, one output) program, other than doing something more interesting with the input than multipling. You can think of the rounding option as a flag used with a comand line interface.

The program will again contain two main parts, one half that will generate a form and the other half that will do some computation on the input and will output the results in a HTML document. This example is quite similar to the last example except one value(round) is used to control the output(acting like a flag for a command line interface), and it also convirts some of the inputed text into numbers which it uses for its computation.

main()
 { int ad,bd,rd,c;
   char *a, *b;

  print content type
  if (there is input)
       { parse input into variables a, b, and r
         convirt a into integer ad
         convirt b into integer bd
	 convirt r into integer rd
         c := floor( (ad * bd) / rd ) * rd;
         printf("< html> ");
         printf("%s times %s = %d",a,b,c);
         printf("< /html > ");
         return 1;}
  else { printf("< html> ");
	 printf("Please type in the two numbers which you want to multiply.");
         printf("< p> < form method=""post"" action=""this file's name""> ");
         printf("< input name=""a""> < p> ");
         printf("< input name=""b""> < p> ");
	 printf("Round down to < SELECT name=""round""> < OPTION SELECTED>  1");
         printf("< OPTION>  10 < OPTION>  100 < /SELECT> < p> ");
         printf("< input type=""submit""> ");
         printf("< /form> ");
         printf("< /html> ");
         return 1;}
         }

Output and examples in other languages

SWORDS - a program wrapper example

Now as a quick side example we will take an existing command line interface program and give it a HTML front end using Perl. The program that we will be using is swords, a little program that I wrote that does pattern matching with with the system's dictionary to help out with cross-word puzzle problems. The program runs something like this: swords < maximum number of words to return> < number of letters in the word> < string(the word) containing a - for unknown letters> . Swords then responds with all of the results that it found(or the maximum that you specified), one on each line.

Yet again the code(this time in Perl) will have two parts the form and the results. But the resulting HTML document will be the parsed data from an input pipe (a call to swords with the inputed parameters). It is for just this reason that I choose to write this example in Perl, it is a little more difficult to do something similar to this in C.

IMPORTANT security reminder: Any time that user input is used in a call to the system, you need to untaint it. Untainting is basically removing any special characters that might do things that you do not want(things like ; | etc). Failure to do this can compromise the security of your server. (I am using "tainted" here in the colloquial sense, the following substitution does not untaint the variable in perl terms.)

#!/bin/perl

print content type;
if(you can read input into input){
        print '< html> ';
        print 'Solutions to your SWORDS request';
        $num = length($input{`pat`});
	$ar = "$num $input{'pat'} $input{'max'}";
	$ar =~ s/\W/ /g;                   #untaint the input
	open(RES,"./swords-simple $ar |"); #The pipe is here
        print"< br> < br> < OL> ";
        while(< RES> )
          { print $_;
            print '< br> ';
            }
       print '< /OL> ';
       print '< /html> ';
       }
else{ print '< html >'; 
      print 'Type your SWORDS request< p> '; 
      print '< form method="post" action="this_file's_name"> ';
      print 'pattern: < input name="a"> ';
      print 'maximum: < select name="max">  < option selected>  25';
      print '< option>  50 < option>  75 < option>  100 < /select>  < p> ';
      print '< input type="submit"> ';
      print '< /html> ';
      }

Output and examples in other languages

Hangman - a fully interactive program

We are now about to start on an example that will illustrate the most complicated class of HTML interface programs, ones who run as real programs do, requiring input during running. The most important thing to note before starting on the example is that even though the program will apppear to be continuously running, in reality it will exit between each request. So any global or local variables will be cleared out each time a request is made. Therefore you have to manage your data in two ways, one by setting up hidden fields in your documents, data that will not be printed by your web browser but that will help in the computation process. You can also make files around the program that will contain data structures, things like arrays, etc. This last option will require a little more programming experience to avoid the various mutual exclusion problems that can occur with more than one process accessing the same file(in the case that there is more than on person running your program at once). But I would not suggest going as far as setting up temporary files containing data that the next reply will use in its computation. Many people will loose interest and not want to continue with the next reply and will then leave temporary files that will use disk space and require later deleting.

The next example will be a hangman program. Information regarding letters already guessed, partiallly found word, and the unknown word itself will be contained in the document(so no peeking!). This information will be split into visable and "invisable" (hidden fields). We will keep 2 variables, one "real" will be the word that we are going to try to guess. Then a "guess" array, which will contain the letters separated by spaces with the last letter being the last letter guessed. The reply will also return a new variable which will be the last guess.

main()
   { form_entry *params = NULL;
     char guess[10];
     char *new,*real;
     int gue,i,g,num;

     params = get_form_entries(ci);
     real = parmval(params,"real");
     print_mimeheader("text/html");

   if(params != NULL) {    
     if (!(strcmp(parmval(params,"guess"),"done")))      /* they guessed */
        { if (!(strcmp(real,parmval(params,"new"))))     /* correct? */
               {printf("You were right.");}
          else {printf("You were WRONG!< p> ");
                printf("It was really %s.",real);}
          return; }
     new = parmval(params,"new");
     sprintf(guess,"%s%c",parmval(params,"guess"),new[0]);
     gue = strlen(guess); 
     num = strlen(real);
     printf("< html> ");
     printf("So far you have guessed:< p> ");
     for (i=0;i< num;i++)       /* print the blanks and guessed letters */
           { for (g=0;g< gue;g++) 
                { if (guess[g] == real[i]) 
                     { printf("%c ",real[i]); /* the letter has been guessed */
                       g=-1;
                       break; } }
             if (g==-1) continue;
             printf("_ "); }    /* the letter is still unknown */
     printf("< p> ");
     if (gue <  6) {        /* they only have 6 guesses */
        printf("Please type your next guess< p> ");
        print_form(real,guess);
        }
     else{            /* out of guesses */
        printf("Sorry the game is over.< p> ");
        printf("The correct answer is %s.< p> ",real); } }
else {     
    real = "first";  \* this needs to be replaced with some random word generator */
    num = strlen(real);
    for (i=1;i< =num;i++)
         { printf("_ "); }
    printf("< html> ");
    printf("Type in your first guess at the above unknown word.< p> ");
    print_form(real,""); } }

print_form(real,guess)
char *real, *guess;
{ printf("< form method=""post"" action=""this file's name""> ");
  printf("< input name = ""new""> < p> ");
  printf("< input type=""hidden"" name=""guess"" value=""");
  printf("%s""> ",guess);
  printf("< input type=""hidden"" name=""real"" value=""");
  printf("%s""> ", real);
  printf("< INPUT TYPE=""reset"" VALUE=""Clear""> ");
  printf("< input type=""submit"" value=""Continue""> ");
  printf("< /form> ");
  printf("Or you can guess the word.< p> ");
  printf("< form method=""post"" action=""/cgi-bin/nik/hangman""> ");
  printf("< input name=""new""> < p> ");
  printf("< input type=""hidden"" name=""guess"" value=""done""> ");
  printf("< input type=""hidden"" name=""real"" value=""");
  printf("%s""> ",real);
  printf("< INPUT TYPE=""reset"" VALUE=""Clear""> ");
  printf("< input type=""submit"" value=""Guess It""> ");
  printf("< /form>  < /html> "); } 

Output and examples in other languages

Assorted CGI Programs of Interest

Comment or Order Gathering program

A simple example of how a comment or order form gathering program could be written. The CGI program just dumps the information it gathered into a file. This information can then be processed by hand or by another program. Five dots are used to separate each result.

#!/bin/perl

require "cgi-lib.pl";

&ReadParse(*input);
if ($input{'done'} eq 'done')
   { print &PrintHeader;
     print '< title>  Thank you for Your Input!< /title> ';
     print '< h1> Thanks for your input.< /h1> ';
     print '< a href="http://blackcat.brynmawr.edu/~nswoboda/prog-html.html">  Go back< /a> ';
     open(FILE, '> >  ./comments.txt'); 
     print FILE < < EOF
name $input{'name'}
contact $input{'contact'}
overall $input{'overall'}
comment	
$input{'comment'}
.....
EOF
     }
else {
    print &PrintHeader;
    print '< title>  Comment < /title> ';
    print '< h1>  Comment Form';
    print '< /h1> < br> ';
    print < < EOF
< form method="post" action="/cgi-bin/nik/comments.pl"> 
Your name:
< input name="name"> < p> 
Your electronic addresses(e-mail, home page etc.)< p> 
< input name="contact"> 
< p> < p> 
Over all rating: < SELECT NAME="overall"> 
< OPTION SELECTED>  0
< OPTION>  1 < OPTION>  2 < OPTION>  3 < OPTION>  4 < OPTION>  5 < OPTION>  6 < OPTION>  7
< OPTION>  8 < OPTION>  9 < OPTION>  10 < /SELECT>  < P> 
< textarea name="comment" rows=10 cols=60> 
< /textarea> 
< input type="hidden" name="done" value="done"> 
< hr> < INPUT TYPE="reset" VALUE="Clear"> 
< input type="submit" value="Submit it!"> 
< /form> 
EOF
    }

Run the program

Look at the program's data file

Appendix A - CGI Libraries

The fillowing list contains various CGI libraries that I have used and am happy with, this list is not intended to contain everything that is out there, but if you have used something that you think should be here drop me a line.

Appendix B - How to use your browser to open your application

First of all you need to be sure that the files either have the correct extension(.cgi) or that they are in the correct location, the cgi-bin directory of your HTTPD server. Once again you should check with the person that set up your web server for more information regarding where and how your server expects to find your cgi programs.

You should also verify that the server will have the correct permissions to execute your program. If you are not sure about this doing a:

chmod 755 file-name

will take care of this problem.

Browser specific information:

  • Nescape - After you have launched netscape you pull down the File menu and select the Open location option. Then type in "http://" the server's name followed by the path for the program's name.
  • Mosaic - After You have launched mosaic you pull down the File menu and select the Open URL option. Then type in "http://" the server's name followed by the path for the program's name.